package com.example.hook.javassist;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Loader;



/**
 * Javassist Hook 实现
 * 
 * Javassist是一个用于Java字节码操作的库
 * 它允许在运行时修改Java类的字节码
 */
public class JavassistHook {
    
    /**
     * 使用Javassist Hook目标类
     * 
     * 注意：这种方式需要在类被加载之前进行Hook
     * 适用于在程序启动时就知道要Hook的类
     */
    public static void hookWithJavassist() {
        try {
            ClassPool pool = ClassPool.getDefault();
            
            // 获取目标类
            CtClass cc = pool.get("com.example.hook.TargetService");
            
            // Hook add方法
            CtMethod addMethod = cc.getDeclaredMethod("add");
            
            // 在方法开始前插入代码
            addMethod.insertBefore(
                "System.out.println(\"[Javassist Hook] add方法被调用，参数: \" + $1 + \", \" + $2);"
            );
            
            // 在方法结束后插入代码（$_表示返回值）
            addMethod.insertAfter(
                "System.out.println(\"[Javassist Hook] add方法原返回值: \" + $_);" +
                "$_ = $_ + 1000;" +  // 修改返回值：加1000
                "System.out.println(\"[Javassist Hook] add方法修改后返回值: \" + $_);"
            );
            
            // Hook getUserInfo方法
            CtMethod getUserInfoMethod = cc.getDeclaredMethod("getUserInfo");
            
            getUserInfoMethod.insertBefore(
                "System.out.println(\"[Javassist Hook] getUserInfo方法被调用，用户ID: \" + $1);"
            );
            
            getUserInfoMethod.insertAfter(
                "System.out.println(\"[Javassist Hook] getUserInfo方法原返回值: \" + $_);" +
                "if ($1 == 777) { $_ = \"Javassist_SuperUser\"; }" +
                "else { $_ = \"[Javassist] \" + $_; }" +
                "System.out.println(\"[Javassist Hook] getUserInfo方法修改后返回值: \" + $_);"
            );
            
            // Hook静态方法formatMessage
            CtMethod formatMessageMethod = cc.getDeclaredMethod("formatMessage");
            
            formatMessageMethod.insertBefore(
                "System.out.println(\"[Javassist Hook] formatMessage静态方法被调用，消息: \" + $1);"
            );
            
            formatMessageMethod.insertAfter(
                "System.out.println(\"[Javassist Hook] formatMessage方法原返回值: \" + $_);" +
                "$_ = \"[JAVASSIST_HOOKED] \" + $1;" +
                "System.out.println(\"[Javassist Hook] formatMessage方法修改后返回值: \" + $_);"
            );
            
            // Hook私有方法 processPrivateData
            CtMethod processPrivateMethod = cc.getDeclaredMethod("processPrivateData");
            
            processPrivateMethod.insertBefore(
                "System.out.println(\"[Javassist Hook] 私有方法processPrivateData被调用，参数: \" + $1);"
            );
            
            processPrivateMethod.insertAfter(
                "System.out.println(\"[Javassist Hook] 私有方法processPrivateData原返回值: \" + $_);" +
                "$_ = \"javassist_private_\" + $1;" +
                "System.out.println(\"[Javassist Hook] 私有方法processPrivateData修改后返回值: \" + $_);"
            );
            
            // 将修改后的类写回磁盘（可选）
            cc.writeFile();
            
            // 转换为Class对象
            cc.toClass();
            
            System.out.println("[Javassist] Hook 完成，类已被修改");
            
            // 注意：cc.toClass()只能调用一次，之后需要detach
            cc.detach();
            
        } catch (Exception e) {
            System.err.println("Javassist Hook 失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 使用自定义ClassLoader进行Hook
     * 这种方式可以避免类加载时机的问题
     */
    public static Class<?> hookWithCustomLoader() {
        try {
            ClassPool pool = ClassPool.getDefault();
            
            // 获取目标类
            CtClass cc = pool.get("com.example.hook.TargetService");
            
            // 修改类名避免冲突
            cc.setName("com.example.hook.HookedTargetService");
            
            // Hook方法（代码同上，这里简化）
            CtMethod addMethod = cc.getDeclaredMethod("add");
            addMethod.insertBefore(
                "System.out.println(\"[Javassist CustomLoader] add方法被调用，参数: \" + $1 + \", \" + $2);"
            );
            addMethod.insertAfter(
                "$_ = $_ * 2;" +  // 返回值乘以2
                "System.out.println(\"[Javassist CustomLoader] add方法修改后返回值: \" + $_);"
            );
            
            // 使用Javassist的Loader加载修改后的类
            Loader loader = new Loader(pool);
            Class<?> hookedClass = loader.loadClass("com.example.hook.HookedTargetService");
            
            System.out.println("[Javassist CustomLoader] 已创建Hooked类: " + hookedClass.getName());
            
            cc.detach();
            return hookedClass;
            
        } catch (Exception e) {
            System.err.println("Javassist CustomLoader Hook 失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 运行时动态Hook - 通过反射和字节码操作
     */
    public static void runtimeHook() {
        try {
            // 这种方式比较复杂，需要配合Instrumentation API
            // 这里提供基本思路
            
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("com.example.hook.TargetService");
            
            // 创建新的方法或修改现有方法
            CtMethod newMethod = CtMethod.make(
                "public int hookedAdd(int a, int b) {" +
                "    System.out.println(\"[Javassist Runtime] 运行时Hook的add方法\");" +
                "    return (a + b) * 5;" +
                "}", cc);
            
            cc.addMethod(newMethod);
            
            // 在实际应用中，需要配合Instrumentation API来实现运行时的类重定义
            System.out.println("[Javassist] 运行时Hook准备完成（需要配合Instrumentation）");
            
            cc.detach();
            
        } catch (Exception e) {
            System.err.println("Javassist Runtime Hook 失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}